Skip to content

Conversation

@Nerixyz
Copy link
Contributor

@Nerixyz Nerixyz commented Nov 6, 2025

PDB doesn't include the typedefs for types, so all types use their full name. For std::string and friends, this means they show up as std::basic_string<char, std::char_traits<char>, std::allocator<char>>.

This PR updates the std::{,w,u8,u16,u32}string(_view) tests to account for this and runs them with PDB.

@Nerixyz Nerixyz requested a review from JDevlieghere as a code owner November 6, 2025 19:33
@Nerixyz Nerixyz requested review from Michael137 and removed request for JDevlieghere November 6, 2025 19:33
@llvmbot llvmbot added the lldb label Nov 6, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 6, 2025

@llvm/pr-subscribers-lldb

Author: nerix (Nerixyz)

Changes

PDB doesn't include the typedefs for types, so all types use their full name. For std::string and friends, this means they show up as std::basic_string&lt;char, std::char_traits&lt;char&gt;, std::allocator&lt;char&gt;&gt;.

This PR updates the std::{,w,u8,u16,u32}string(_view) tests to account for this and runs them with PDB.


Full diff: https://github.com/llvm/llvm-project/pull/166833.diff

4 Files Affected:

  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py (+52-29)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py (+46-28)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py (+12-4)
  • (modified) lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py (+12-4)
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py
index 6a27b5d2f0780..00047e419de37 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string/TestDataFormatterStdString.py
@@ -11,6 +11,8 @@
 
 
 class StdStringDataFormatterTestCase(TestBase):
+    TEST_WITH_PDB_DEBUG_INFO = True
+
     def setUp(self):
         # Call super's setUp().
         TestBase.setUp(self)
@@ -18,6 +20,17 @@ def setUp(self):
         self.main_spec = lldb.SBFileSpec("main.cpp")
         self.namespace = "std"
 
+    def _makeStringName(self, typedef: str, char_type: str, allocator=None):
+        if allocator is None:
+            allocator = self.namespace + "::allocator"
+
+        if self.getDebugInfo() == "pdb":
+            return f"{self.namespace}::basic_string<{char_type}, std::char_traits<{char_type}>, {allocator}<{char_type}>>"
+
+        if typedef.startswith("::"):
+            return self.namespace + typedef
+        return typedef
+
     def do_test(self):
         """Test that that file and class static variables display correctly."""
         (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
@@ -36,10 +49,17 @@ def cleanup():
         # Execute the cleanup function during test case tear down.
         self.addTearDownHook(cleanup)
 
-        ns = self.namespace
+        string_name = self._makeStringName("::string", "char")
+        wstring_name = self._makeStringName("::wstring", "wchar_t")
+        custom_string_name = self._makeStringName(
+            "CustomString", "char", allocator="CustomAlloc"
+        )
+        custom_wstring_name = self._makeStringName(
+            "CustomWString", "wchar_t", allocator="CustomAlloc"
+        )
 
         # Check 'S' pre-assignment.
-        self.expect("frame variable S", substrs=['(%s::wstring) S = L"!!!!"' % ns])
+        self.expect("frame variable S", substrs=[f'({wstring_name}) S = L"!!!!"'])
 
         thread.StepOver()
 
@@ -54,34 +74,31 @@ def cleanup():
         )
 
         self.expect_expr(
-            "s", result_type=ns + "::wstring", result_summary='L"hello world! מזל טוב!"'
+            "s", result_type=wstring_name, result_summary='L"hello world! מזל טוב!"'
         )
 
-        self.expect_expr(
-            "q", result_type=ns + "::string", result_summary='"hello world"'
-        )
+        self.expect_expr("q", result_type=string_name, result_summary='"hello world"')
 
         self.expect_expr(
             "Q",
-            result_type=ns + "::string",
+            result_type=string_name,
             result_summary='"quite a long std::strin with lots of info inside it"',
         )
 
         self.expect(
             "frame variable",
             substrs=[
-                '(%s::wstring) wempty = L""' % ns,
-                '(%s::wstring) s = L"hello world! מזל טוב!"' % ns,
-                '(%s::wstring) S = L"!!!!!"' % ns,
+                f'({wstring_name}) wempty = L""',
+                f'({wstring_name}) s = L"hello world! מזל טוב!"',
+                f'({wstring_name}) S = L"!!!!!"',
                 "(const wchar_t *) mazeltov = 0x",
                 'L"מזל טוב"',
-                '(%s::string) empty = ""' % ns,
-                '(%s::string) q = "hello world"' % ns,
-                '(%s::string) Q = "quite a long std::strin with lots of info inside it"'
-                % ns,
-                "(%s::string *) null_str = nullptr" % ns,
-                '(CustomString) custom_str = "hello!"',
-                '(CustomWString) custom_wstr = L"hello!"',
+                f'({string_name}) empty = ""',
+                f'({string_name}) q = "hello world"',
+                f'({string_name}) Q = "quite a long std::strin with lots of info inside it"',
+                f"({string_name} *) null_str = nullptr",
+                f'({custom_string_name}) custom_str = "hello!"',
+                f'({custom_wstring_name}) custom_wstr = L"hello!"',
             ],
         )
 
@@ -136,19 +153,26 @@ def do_test_multibyte(self):
             self, "Set break point at this line.", self.main_spec
         )
 
-        ns = self.namespace
+        u16string_name = self._makeStringName("::u16string", "char16_t")
+        u32string_name = self._makeStringName("::u32string", "char32_t")
+        custom_u16string_name = self._makeStringName(
+            "CustomStringU16", "char16_t", allocator="CustomAlloc"
+        )
+        custom_u32string_name = self._makeStringName(
+            "CustomStringU32", "char32_t", allocator="CustomAlloc"
+        )
 
         self.expect(
             "frame variable",
             substrs=[
-                '(%s::u16string) u16_string = u"ß水氶"' % ns,
-                '(%s::u16string) u16_empty = u""' % ns,
-                '(%s::u32string) u32_string = U"🍄🍅🍆🍌"' % ns,
-                '(%s::u32string) u32_empty = U""' % ns,
-                '(CustomStringU16) custom_u16 = u"ß水氶"',
-                '(CustomStringU16) custom_u16_empty = u""',
-                '(CustomStringU32) custom_u32 = U"🍄🍅🍆🍌"',
-                '(CustomStringU32) custom_u32_empty = U""',
+                f'({u16string_name}) u16_string = u"ß水氶"',
+                f'({u16string_name}) u16_empty = u""',
+                f'({u32string_name}) u32_string = U"🍄🍅🍆🍌"',
+                f'({u32string_name}) u32_empty = U""',
+                f'({custom_u16string_name}) custom_u16 = u"ß水氶"',
+                f'({custom_u16string_name}) custom_u16_empty = u""',
+                f'({custom_u32string_name}) custom_u32 = U"🍄🍅🍆🍌"',
+                f'({custom_u32string_name}) custom_u32_empty = U""',
             ],
         )
 
@@ -271,9 +295,8 @@ def do_test_embedded_null(self):
         self.expect(
             "frame variable",
             substrs=[
-                '(%s::string) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"' % ns,
-                '(%s::wstring) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"'
-                % ns,
+                f'({self._makeStringName("::string", "char")}) IHaveEmbeddedZeros = "a\\0b\\0c\\0d"',
+                f'({self._makeStringName("::wstring", "wchar_t")}) IHaveEmbeddedZerosToo = L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
             ],
         )
 
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py
index 181141886c5a2..884e689c21655 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/string_view/TestDataFormatterStdStringView.py
@@ -11,6 +11,8 @@
 
 
 class StdStringViewDataFormatterTestCase(TestBase):
+    TEST_WITH_PDB_DEBUG_INFO = True
+
     def setUp(self):
         # Call super's setUp().
         TestBase.setUp(self)
@@ -20,6 +22,12 @@ def setUp(self):
             "main.cpp", "// Break here to look at bad string view."
         )
 
+    def _makeStringName(self, typedef: str, char_type: str):
+        if self.getDebugInfo() == "pdb":
+            return f"std::basic_string_view<{char_type}, std::char_traits<{char_type}>>"
+
+        return typedef
+
     def do_test(self):
         """Test that that file and class static variables display correctly."""
         self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET)
@@ -51,39 +59,49 @@ def cleanup():
         # Execute the cleanup function during test case tear down.
         self.addTearDownHook(cleanup)
 
-        self.expect_var_path("wempty", type="std::wstring_view", summary='L""')
+        string_view_name = self._makeStringName("std::string_view", "char")
+        wstring_view_name = self._makeStringName("std::wstring_view", "wchar_t")
+        u16string_view_name = self._makeStringName("std::u16string_view", "char16_t")
+        u32string_view_name = self._makeStringName("std::u32string_view", "char32_t")
+        string_name = (
+            "std::basic_string<char, std::char_traits<char>, std::allocator<char>>"
+            if self.getDebugInfo() == "pdb"
+            else "std::string"
+        )
+
+        self.expect_var_path("wempty", type=wstring_view_name, summary='L""')
         self.expect_var_path(
-            "s", type="std::wstring_view", summary='L"hello world! מזל טוב!"'
+            "s", type=wstring_view_name, summary='L"hello world! מזל טוב!"'
         )
-        self.expect_var_path("S", type="std::wstring_view", summary='L"!!!!"')
-        self.expect_var_path("empty", type="std::string_view", summary='""')
-        self.expect_var_path("q_source", type="std::string", summary='"hello world"')
-        self.expect_var_path("q", type="std::string_view", summary='"hello world"')
+        self.expect_var_path("S", type=wstring_view_name, summary='L"!!!!"')
+        self.expect_var_path("empty", type=string_view_name, summary='""')
+        self.expect_var_path("q_source", type=string_name, summary='"hello world"')
+        self.expect_var_path("q", type=string_view_name, summary='"hello world"')
         self.expect_var_path(
             "Q",
-            type="std::string_view",
+            type=string_view_name,
             summary='"quite a long std::strin with lots of info inside it"',
         )
         self.expect_var_path(
-            "IHaveEmbeddedZeros", type="std::string_view", summary='"a\\0b\\0c\\0d"'
+            "IHaveEmbeddedZeros", type=string_view_name, summary='"a\\0b\\0c\\0d"'
         )
         self.expect_var_path(
             "IHaveEmbeddedZerosToo",
-            type="std::wstring_view",
+            type=wstring_view_name,
             summary='L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
         )
-        self.expect_var_path("u16_string", type="std::u16string_view", summary='u"ß水氶"')
-        self.expect_var_path("u16_empty", type="std::u16string_view", summary='u""')
+        self.expect_var_path("u16_string", type=u16string_view_name, summary='u"ß水氶"')
+        self.expect_var_path("u16_empty", type=u16string_view_name, summary='u""')
         self.expect_var_path(
-            "u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"'
+            "u32_string", type=u32string_view_name, summary='U"🍄🍅🍆🍌"'
         )
-        self.expect_var_path("u32_empty", type="std::u32string_view", summary='U""')
+        self.expect_var_path("u32_empty", type=u32string_view_name, summary='U""')
 
         # GetSummary returns None so can't be checked by expect_var_path, so we
         # use the str representation instead
         null_obj = self.frame().GetValueForVariablePath("null_str")
         self.assertEqual(null_obj.GetSummary(), "Summary Unavailable")
-        self.assertEqual(str(null_obj), "(std::string_view *) null_str = nullptr")
+        self.assertEqual(str(null_obj), f"({string_view_name} *) null_str = nullptr")
 
         self.runCmd("n")
 
@@ -108,37 +126,37 @@ def cleanup():
 
         self.expect_expr(
             "s",
-            result_type="std::wstring_view",
+            result_type=wstring_view_name,
             result_summary='L"hello world! מזל טוב!"',
         )
 
-        self.expect_var_path("wempty", type="std::wstring_view", summary='L""')
+        self.expect_var_path("wempty", type=wstring_view_name, summary='L""')
         self.expect_var_path(
-            "s", type="std::wstring_view", summary='L"hello world! מזל טוב!"'
+            "s", type=wstring_view_name, summary='L"hello world! מזל טוב!"'
         )
-        self.expect_var_path("S", type="std::wstring_view", summary='L"!!!!"')
-        self.expect_var_path("empty", type="std::string_view", summary='""')
-        self.expect_var_path("q_source", type="std::string", summary='"Hello world"')
-        self.expect_var_path("q", type="std::string_view", summary='"Hello world"')
+        self.expect_var_path("S", type=wstring_view_name, summary='L"!!!!"')
+        self.expect_var_path("empty", type=string_view_name, summary='""')
+        self.expect_var_path("q_source", type=string_name, summary='"Hello world"')
+        self.expect_var_path("q", type=string_view_name, summary='"Hello world"')
         self.expect_var_path(
             "Q",
-            type="std::string_view",
+            type=string_view_name,
             summary='"quite a long std::strin with lots of info inside it"',
         )
         self.expect_var_path(
-            "IHaveEmbeddedZeros", type="std::string_view", summary='"a\\0b\\0c\\0d"'
+            "IHaveEmbeddedZeros", type=string_view_name, summary='"a\\0b\\0c\\0d"'
         )
         self.expect_var_path(
             "IHaveEmbeddedZerosToo",
-            type="std::wstring_view",
+            type=wstring_view_name,
             summary='L"hello world!\\0てざ ル゜䋨ミ㠧槊 きゅへ狦穤襩 じゃ馩リョ 䤦監"',
         )
-        self.expect_var_path("u16_string", type="std::u16string_view", summary='u"ß水氶"')
-        self.expect_var_path("u16_empty", type="std::u16string_view", summary='u""')
+        self.expect_var_path("u16_string", type=u16string_view_name, summary='u"ß水氶"')
+        self.expect_var_path("u16_empty", type=u16string_view_name, summary='u""')
         self.expect_var_path(
-            "u32_string", type="std::u32string_view", summary='U"🍄🍅🍆🍌"'
+            "u32_string", type=u32string_view_name, summary='U"🍄🍅🍆🍌"'
         )
-        self.expect_var_path("u32_empty", type="std::u32string_view", summary='U""')
+        self.expect_var_path("u32_empty", type=u32string_view_name, summary='U""')
 
         self.runCmd("cont")
         self.expect(
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py
index b983ee175d389..dda97945f9b23 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string/TestDataFormatterStdU8String.py
@@ -11,18 +11,26 @@
 
 
 class StdU8StringDataFormatterTestCase(TestBase):
+    TEST_WITH_PDB_DEBUG_INFO = True
+
     def do_test(self):
         lldbutil.run_to_source_breakpoint(
             self, "Set break point at this line.", lldb.SBFileSpec("main.cpp")
         )
 
+        string_name = (
+            "std::basic_string<char8_t, std::char_traits<char8_t>, std::allocator<char8_t>>"
+            if self.getDebugInfo() == "pdb"
+            else "std::u8string"
+        )
+
         self.expect(
             "frame variable",
             substrs=[
-                '(std::u8string) u8_string_small = u8"🍄"',
-                '(std::u8string) u8_string = u8"❤️👍📄📁😃🧑‍🌾"',
-                '(std::u8string) u8_empty = u8""',
-                '(std::u8string) u8_text = u8"ABCd"',
+                f'({string_name}) u8_string_small = u8"🍄"',
+                f'({string_name}) u8_string = u8"❤️👍📄📁😃🧑‍🌾"',
+                f'({string_name}) u8_empty = u8""',
+                f'({string_name}) u8_text = u8"ABCd"',
             ],
         )
 
diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py
index 1e35a0f6bb040..6cf72d18a864f 100644
--- a/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py
+++ b/lldb/test/API/functionalities/data-formatter/data-formatter-stl/generic/u8string_view/TestDataFormatterStdU8StringView.py
@@ -11,18 +11,26 @@
 
 
 class StdU8StringViewDataFormatterTestCase(TestBase):
+    TEST_WITH_PDB_DEBUG_INFO = True
+
     def do_test(self):
         lldbutil.run_to_source_breakpoint(
             self, "Set break point at this line.", lldb.SBFileSpec("main.cpp")
         )
 
+        string_view_name = (
+            "std::basic_string_view<char8_t, std::char_traits<char8_t>>"
+            if self.getDebugInfo() == "pdb"
+            else "std::u8string_view"
+        )
+
         self.expect(
             "frame variable",
             substrs=[
-                '(std::u8string_view) u8_string_small = u8"🍄"',
-                '(std::u8string_view) u8_string = u8"❤️👍📄📁😃🧑‍🌾"',
-                '(std::u8string_view) u8_empty = u8""',
-                '(std::u8string_view) u8_text = u8"ABCd"',
+                f'({string_view_name}) u8_string_small = u8"🍄"',
+                f'({string_view_name}) u8_string = u8"❤️👍📄📁😃🧑‍🌾"',
+                f'({string_view_name}) u8_empty = u8""',
+                f'({string_view_name}) u8_text = u8"ABCd"',
             ],
         )
 

@github-actions
Copy link

github-actions bot commented Nov 6, 2025

✅ With the latest revision this PR passed the Python code formatter.

@Nerixyz Nerixyz merged commit 311d115 into llvm:main Nov 7, 2025
10 checks passed
@Nerixyz Nerixyz deleted the fix/lldb-pdb-string-and-view branch November 7, 2025 14:15
vinay-deshmukh pushed a commit to vinay-deshmukh/llvm-project that referenced this pull request Nov 8, 2025
PDB doesn't include the typedefs for types, so all types use their full
name. For `std::string` and friends, this means they show up as
`std::basic_string<char, std::char_traits<char>, std::allocator<char>>`.

This PR updates the `std::{,w,u8,u16,u32}string(_view)` tests to account
for this and runs them with PDB.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants